#include "server.h"

#define _TRY_TIMES              10      // 尝试发送次数

void thrd_sender(struct sender_ctl *sender_ctl)
{
    int res;
    int i;
    char buf[100];
    int sender_idx=sender_ctl->sender_idx;
    THRD_MSGQ msgq=share_info->sender_msgq[sender_idx];
    struct listp_link *msgq_todo=&sender_ctl->msgq_todo;
    struct listp_link msgq_recv;
    struct listp_link msgq_later;
    time_t curr_ts;
    time_t later_ts=curr_timestamp(NULL);
    int *smtp_idxes;
    int smtp_idx;
    int smtp_ready_num;
    struct host_addr_info *smtp_ready;
    struct host_addr_info *smtp_backup;
    unsigned int send_num=0;
    unsigned int todo_num;
    SMTP smtp;
    struct mail *mail;
    FILE *fp;
    char oldpath[LONG_FILE_NM_SIZE+1];
    char newpath[LONG_FILE_NM_SIZE+1];

    listp_init(&msgq_later);
    if(sender_idx == SENDER_VIP_IDX)
    {
        smtp_ready_num=share_info->smtp_ready_vip_num;
        smtp_ready=share_info->smtp_ready_vip;
        smtp_backup=share_info->smtp_backup_vip;
    }
    else
    {
        smtp_ready_num=share_info->smtp_ready_num;
        smtp_ready=share_info->smtp_ready;
        smtp_backup=share_info->smtp_backup;
    }
    ALLOC_MULTI_DOERR(smtp_idxes, int, smtp_ready_num, return);

    while(1)
    {
        if((res=thrd_msgq_recv(msgq, 10*1000, &msgq_recv)))
        {
            if(res != RET_ERR_TIMEOUT)
                errlog("%s: sender(%d) thrd_msgq_recv fail, res:%d, "
                        "IMPOSSIBLE!!!",
                        __func__, sender_idx, res);
        }
        if(share_info->_errlog_.tracking)
            if((res=listp_count(&msgq_recv)) > 0)
                errlog("%s: sender(%d) recv %d msg",
                        __func__, sender_idx, res);
        listp_append(&msgq_recv, msgq_todo);
        if((curr_ts=curr_timestamp(NULL)) - later_ts >
                SECOND_OF_MINUTE(1))
        {
            listp_append(&msgq_later, msgq_todo);
            later_ts=curr_ts;
        }
        if((todo_num=listp_count(msgq_todo)) == 0)
            continue;

        for(i=0; i<smtp_ready_num; i++)
            smtp_idxes[i]=i;
        random_array_int(smtp_idxes, smtp_ready_num);
        for(i=0; i<smtp_ready_num; i++)
        {
            smtp_idx=smtp_idxes[i];
            smtp=sender_ctl->smtp_ready[smtp_idx];
            if((res=smtp_hello(smtp)) == 0)
                break;
            // hello出错，则回到recv
            errlog("%s: sender(%d) smtp_hello ready(%s) fail, res:%d, "
                    "ATTENTION!!!",
                    __func__, sender_idx,
                    smtp_ready[smtp_idx].host, res);
        }
        if(i == smtp_ready_num)
        {
            if(sender_ctl->smtp_backup)
            {
                smtp=sender_ctl->smtp_backup;
                if((res=smtp_hello(smtp)))
                {
                    errlog("%s: sender(%d) smtp_hello backup(%s) fail, "
                            "res:%d, ATTENTION!!! CHECK IT UP!!!",
                            __func__, sender_idx,
                            smtp_backup->host, res);
                    sleep(30);
                    continue;
                }
                smtp_idx=-1;
            }
            else
            {
                errlog("%s: sender(%d) no smtp backup, "
                        "ATTENTION!!! CHECK IT UP!!!",
                        __func__, sender_idx);
                sleep(30);
                continue;
            }
        }
        if(share_info->_errlog_.tracking)
            errlog("%s: sender(%d) choose smtp(%d)",
                    __func__, sender_idx, smtp_idx);

        while(!listp_is_empty(msgq_todo))
        {
            mail=listp_entry(msgq_todo->next, struct mail, link);
            listp_del(&mail->link);
            todo_num--;

            // 发送
            if((res=smtp_send(smtp, mail->rcpt,
                            mail->from,
                            BUF_IS_CLR(mail->reply)?
                            (char *)NULL : mail->reply,
                            mail->subject, mail->body, (char **)NULL)))
            {
                // send出错，则发下一封，本封留到下一次发送
                errlog("%s: smtp_send(%s) fail, mail(%s) mailto(%s), "
                        "res:%d, INVALID!!!",
                        __func__,
                        (smtp_idx == -1) ?
                        share_info->smtp_backup->host :
                        share_info->smtp_ready[smtp_idx].host,
                        mail->file, mail->rcpt, res);
                if((++mail->try_times) == _TRY_TIMES)
                {
                    sprintf(oldpath, "%s/send/%s",
                            share_info->_mail_.mail_store_dir,
                            mail->file);
                    sprintf(newpath, "%s/discard/%s",
                            share_info->_mail_.mail_store_dir,
                            mail->file);
                    rename(oldpath, newpath);
                    errlog("%s: mail(%s) exceed try times",
                            __func__, mail->file); 
                    free(mail->body); free(mail);
                }
                else
                {
                    listp_add_tail(&mail->link, &msgq_later);
                }
                continue;
            }
            if(share_info->_errlog_.tracking)
                errlog("%s: sender(%d) smtp_send succeed",
                        __func__, sender_idx);

            // 备份邮件头
            sprintf(oldpath, "%s/send/%s",
                    share_info->_mail_.mail_store_dir, mail->file);
            sprintf(newpath, "%s/%.8s.bak",
                    share_info->_mail_.mail_store_dir, mail->file);
            if((fp=fopen(newpath, "a")))
            {
                timestamp_fmt(curr_timestamp_str(buf), NULL, buf, NULL);
                if(sender_idx == SENDER_VIP_IDX)
                    fprintf(fp, "%s vip %s %s %s\n",
                            buf, mail->from, mail->rcpt, mail->subject);
                else
                    fprintf(fp, "%s nor %s %s %s\n",
                            buf, mail->from, mail->rcpt, mail->subject);
                fclose(fp);
                unlink(oldpath);
            }
            else
            {
                sprintf(newpath, "%s.bak", oldpath);
                rename(oldpath, newpath);
            }
            if(share_info->_errlog_.tracking)
                errlog("%s: sender(%d) backup %s -> %s",
                        __func__, sender_idx, oldpath, newpath);

            // 释放mail
            free(mail->body); free(mail);

            send_num++;
            pthread_mutex_lock(&share_info->stat_lock);
            share_info->sender_stat[sender_idx].send_num=send_num;
            share_info->sender_stat[sender_idx].todo_num=todo_num;
            pthread_mutex_unlock(&share_info->stat_lock);
        }

        smtp_quit(smtp);
    }
}
